/* ----------------------------------------------------------------------------
* File: command_handler_impl.cpp
*
* Desc: Implementation of command event handler for Skype API
*
* Created: 29/06/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#include <list>
#include <sstream>
#include <string>

#include "attach_handler_impl.h"
#include "command_handler_impl.h"
#include "commands_define.h"
#include "message_queue_impl.h"
#include "quiz_dictionary_impl.h"
#include "quiz_user_profile_impl.h"
#include "utils.h"

#define QUIZ_PROMPT_TIME		20	//sec
#define QUIZ_DELAY_QUESTION		10	//sec
#define QUIZ_QUESTION_TIME		60	//sec

namespace SkypePlugin
{
	std::auto_ptr<SkypeProtection::APICommandHandler> CreateSkypeServiceEventHandler(const APICommandHandlerParams& params)
	{
		std::auto_ptr<SkypeProtection::APICommandHandler> handler;
		try
		{
			std::auto_ptr<APICommandHandlerImpl> obj(new APICommandHandlerImpl());
			obj->Init(params);
			handler = obj;
		}
		catch(...)
		{

		}
		return handler;
	}
}

namespace SkypePlugin
{
	APICommandHandlerImpl::APICommandHandlerImpl()
	{
		m_Logger = Common::CreateDebugLogger();
		if (!m_Logger.get())
			throw Common::Exception("SkypeServiceEventHandler: ERROR - Unable to create debug logger");
	}
		
	APICommandHandlerImpl::~APICommandHandlerImpl()
	{
	}

	void APICommandHandlerImpl::Init(const APICommandHandlerParams& params) 
		throw (Common::Exception)
	{
		CheckParams(params);
		m_Params = params;
	}

	void APICommandHandlerImpl::CheckParams(const APICommandHandlerParams& params)
	{
		if (params.Controller == NULL)
			throw Common::Exception("Controller object is null");
		if (params.ServiceHandle == NULL)
			throw Common::Exception("Service handle object is null");
	}
		
	void APICommandHandlerImpl::OnMessageStatus(SKYPE4COMLib::IChatMessage* pMessage, SKYPE4COMLib::TChatMessageStatus Status)
	{
		switch(Status)
		{
		case SKYPE4COMLib::cmsReceived:
			{
				_bstr_t body = pMessage->GetBody();
				char* msg = (char*)body;

				m_Logger->Print("SkypeServiceEventHandler: new message: %s, status - %d", msg, Status);
				if (CheckControlCommand(pMessage) == Common::SKYPE_SUCCESS)
					return;
			}
			break;

		case SKYPE4COMLib::cmsRead:
			break;

		case SKYPE4COMLib::cmsSending:
			break;

		case SKYPE4COMLib::cmsSent:
			break;
		}
	}
		
	QuizCore::QuizModule* APICommandHandlerImpl::FindQuizModule(const std::string& ChatName)
	{
		using namespace ModuleManagement;
		std::vector<BaseModule*> modules = m_Params.Controller->FindModulesByChat(ChatName, MODULE_TYPE_QUIZ);
		return (modules.empty()) ? NULL : reinterpret_cast<QuizCore::QuizModule*>(modules.front());
	}

	Common::Error APICommandHandlerImpl::CheckControlCommand(SKYPE4COMLib::IChatMessage* pMessage)
	{
		_bstr_t body = pMessage->GetBody();
		char* msg = (char*)body;
		char* pdest = NULL;
		int pos;

		std::string str((char*)pMessage->GetBody());
		std::istringstream ist(str);
		std::list<std::string> commandWords;
		std::string tmp;
		while (ist >> tmp)
			commandWords.push_back(tmp);

		try
		{
			std::string first = commandWords.front();
			std::string chat = (char*)pMessage->ChatName;
			commandWords.pop_front();
			if (first == QUIZ_MODULE_COMMAND)
				return ProcessQuizCommand(commandWords, chat);

			if (first == TALK_MODULE_COMMAND)
				return ProcessTalkCommand(commandWords, chat);

			if (first == WEATHER_MODULE_COMMAND)
				return ProcessWeatherCommand(commandWords, chat);
		}
		catch(const Common::Exception& ex)
		{
			m_Logger->Print("SkypeServiceEventHandler: EXCEPTION - %s", ex.GetStr().c_str());
			return Common::SKYPE_ERROR;
		}
		catch(...)
		{
			m_Logger->Print("SkypeServiceEventHandler: EXCEPTION - unexpected");
			return Common::SKYPE_ERROR;
		}

		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::ProcessQuizCommand(const std::list<std::string>& words, const std::string& ChatName)
	{
		std::string word = words.front();
		if (word == START_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz START command");
			return StartQuiz(ChatName);
		}
		else if (word == STOP_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz STOP command");
			return StopQuiz(ChatName);
		}
		else if (word == STATISTIC_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz STATISTICS command");
			return StatisticQuiz(ChatName);
		}
		else if (word == USER_STATISTIC_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz USER_STATISTICS command");
			return UserStatisticQuiz(ChatName);
		}
		else if (word == PROMPT_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz PROMPT command");
			return PromptQuiz(ChatName);
		}
		else if (word == NEXT_QUESTION_COMMAND)
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz NEXT_QUESTION command");
			return NextQuestionQuiz(ChatName);
		}
		else
		{
			m_Logger->Print("SkypeServiceEventHandler: Quiz UNKNOWN command");
			return Common::SKYPE_ERROR;
		}
	}

	Common::Error APICommandHandlerImpl::ProcessTalkCommand(const std::list<std::string>& words, const std::string& ChatName)
	{
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::ProcessWeatherCommand(const std::list<std::string>& words, const std::string& ChatName)
	{
		return Common::SKYPE_SUCCESS;
	}

	bool APICommandHandlerImpl::IsQuizModule(ModuleManagement::BaseModule *module)
	{
		return (module->GetType() == ModuleManagement::MODULE_TYPE_QUIZ);
	}

	Common::Error APICommandHandlerImpl::StartQuiz(const std::string& ChatName)
		throw(Common::Exception)
	{
		using namespace QuizCore;
		using namespace ModuleManagement;

		// Quiz can be started once for chat
		QuizModule* quiz = FindQuizModule(ChatName);
		if (quiz != NULL)
			throw Common::Exception("SkypeServiceEventHandler: StartQuiz() - Quiz is already started");

		std::auto_ptr<DictionaryManager> dict(new QuizDictionaryManagerImpl("C:\\ak-skype-plugin\\questions.txt"));
		std::auto_ptr<UserProfileManager> profile(new QuizUserProfileManagerImpl("C:\\ak-skype-plugin\\users.txt"));
		std::auto_ptr<AttachHandlerImpl> attachHandler(new AttachHandlerImpl(m_Params.ServiceHandle));

		QuizModuleParams params;
		params.Dict = dict.release();
		params.UserProfile = profile.release();
		params.AttachHandler = attachHandler.release();
		params.ChatName = ChatName;
		params.AutoPrompts = true;
		params.PromptTime = QUIZ_PROMPT_TIME;
		params.DelayQuestion = QUIZ_DELAY_QUESTION;
		params.QuestionTimeout = QUIZ_QUESTION_TIME;

		// Create quiz module
		std::auto_ptr<BaseModule> module = CreateQuizModule(params);
		if (!module.get())
			throw Common::Exception("SkypeHandler: Unable to create quiz module");
		m_Logger->Print("SkypeServiceEventHandler: StartQuizModule() - module is created(OK)");

		// Register module
		size_t Id; 
		if (m_Params.Controller->RegisterModule(module.release(), ChatName, Id) != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to register quiz module");
		m_Logger->Print("SkypeServiceEventHandler: StartQuizModule() - module is registered, ID - %d (OK)", Id);

		// Start module
		BaseModule* quizModule = const_cast<BaseModule*>(m_Params.Controller->FindModuleByID(Id));
		if (!quizModule)
			throw Common::Exception("SkypeServiceEventHandler: StartQuizModule: ERROR - Unable to find module by id");
		if (quizModule->Start() != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to start quiz module");

		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::StopQuiz(const std::string& ChatName)
		throw(Common::Exception)
	{
		using namespace QuizCore;

		// Find module
		QuizModule* quiz = FindQuizModule(ChatName);
		if (!quiz)
			throw Common::Exception("SkypeServiceEventHandler: StopQuiz() - WARNING: quiz module isn't started");

		// Stop module
		quiz->Stop();
		m_Logger->Print("SkypeServiceEventHandler: StopQuiz() - module is stopped(OK)");

		// Unregister module
		if (m_Params.Controller->UnregisterModule(quiz->GetID()) != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to unregister quiz module");
		m_Logger->Print("SkypeServiceEventHandler: StopQuiz() - module is unregistered, ID - %d (OK)", quiz->GetID());

		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::StatisticQuiz(const std::string& ChatName)
		throw(Common::Exception)
	{
		using namespace QuizCore;

		QuizModule* quiz = FindQuizModule(ChatName);
		if (!quiz)
			throw Common::Exception("SkypeServiceEventHandler: StatisticQuiz() - WARNING: quiz module isn't started");

		if (quiz->ShowCommonStatistics() != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to show common statistics from quiz module");
		m_Logger->Print("SkypeServiceEventHandler: StatisticsQuizModule - show common statistics (OK)");

		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::UserStatisticQuiz(const std::string& ChatName)
		throw(Common::Exception)
	{
		using namespace QuizCore;

		QuizModule* quiz = FindQuizModule(ChatName);
		if (!quiz)
			throw Common::Exception("SkypeServiceEventHandler: UserStatisticQuiz() - WARNING: quiz module isn't started");
		
		if (quiz->ShowUserStatistics() != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to show user statistics from quiz module");
		m_Logger->Print("SkypeServiceEventHandler: UserStatisticQuiz - show user statistics (OK)");

		return Common::SKYPE_SUCCESS;
	}

	Common::Error APICommandHandlerImpl::PromptQuiz(const std::string& ChatName)
	{
		using namespace QuizCore;

		QuizModule* quiz = FindQuizModule(ChatName);
		if (!quiz)
			throw Common::Exception("SkypeServiceEventHandler: PromptQuiz() - WARNING: quiz module isn't started");

		if (quiz->ShowPrompt() != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to show prompt from quiz module");
		m_Logger->Print("SkypeServiceEventHandler: PromptQuiz - show prompt (OK)");
	}

	Common::Error APICommandHandlerImpl::NextQuestionQuiz(const std::string& ChatName)
		throw(Common::Exception)
	{
		using namespace QuizCore;

		QuizModule* quiz = FindQuizModule(ChatName);
		if (!quiz)
			throw Common::Exception("SkypeServiceEventHandler: NextQuestionQuiz() - WARNING: quiz module isn't started");

		if (quiz->NextQuestion() != Common::SKYPE_SUCCESS)
			throw Common::Exception("SkypeServiceEventHandler: Unable to process of next question for quiz module");
		m_Logger->Print("SkypeServiceEventHandler: NextQuestionQuiz - next question (OK)");

		return Common::SKYPE_SUCCESS;
	}
}
